BP算法(逆向传播算法)一种训练神经网络的算法,通过误差逆向传播和梯度下降算法,训练网络中的参数。具体内容可以参考吴恩达coursera课程的课件http://pan.baidu.com/s/1qYxLdpE。
网络模型
给定训练数据$\{(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),\cdots,(x^{(m)},y^{(m)})\}$,在多类分类(这里假设$K$类)情况下,数据标签$y\in\mathbb{R}^{K}$,例如:
$$y\in\left\{ \left [ \begin{matrix}
1 \\
0 \\
0 \\
0 \end{matrix}\right ],\left [ \begin{matrix}
0 \\
1 \\
0 \\
0 \end{matrix}\right ],\left [ \begin{matrix}
0 \\
0 \\
1 \\
0 \end{matrix}\right ],\left [ \begin{matrix}
0 \\
0 \\
0 \\
1 \end{matrix}\right ],\right \}
$$
神经网络模型如下:
算法描述
代价函数(Cost function)
机器学习中的模型训练算法基本上都是最小化代价函数,比如logistic regression的代价函数如下:
$$J(\theta)=-\frac{1}{m}\left [ \sum_{i=1}^{m}y^{(i)}\log h_{\theta}(x^{(i)})+(1-y^{(i)})\log(1-h_{\theta}(x^{(i)}))\right ] +\frac{\lambda}{2m}\sum_{j=1}^{m}\theta_j^2$$
logistic regression的训练过程就是最小化上面代价函数。在神经网络中,每个神经元使用的是sigmoid函数,其代价函数如下:
$$h_{\Theta}(x)\in \mathbb{R}^{K} \quad (h_{\Theta}(x))_i = i^{th}output \\
J(\Theta)=-\frac{1}{m}\left [ \sum_{i=1}^{m}\sum_{k=1}^{K}y^{(i)}_k\log (h_{\Theta}(x^{(i)}))_k+(1-y^{(i)}_k)\log(1-(h_{\Theta}(x^{(i)}))_k)\right ]+\frac{\lambda}{2m}\sum_{l=1}^{L-1}\sum_{i=1}^{s_l}\sum_{j=1}^{s_l+1}(\Theta^{(l)}_{ji})^2$$
其中,$L$表示神经网络的层数,$s_l$表示第$l$层的神经元的个数。训练神经网络的目的就是最小化上面的代价函数,而BP算法正是为最小化该代价函数而设计的。
前向传播(Forward propagation)
记$a^{(i)}$表示第$i$层神经元的输出,则前向传播的计算过程如下:
逆向传播(Back propagation)
记$\delta^{(l)}_j$表示第$l$层的第$j$个神经元出的误差,就本文中的神经网络模型而言,逆向传播的计算过程如下:
对于第四层的每个神经元,其输出结果的误差为
$$\delta^{(4)}_j=a^{(4)}_j-y_j$$
前面几层的神经元的输出结果误差为:
$$\delta^{(3)}=(\Theta^{(3)})^T\delta^{(4)}.*g’(z^{(3)}) \quad g’(z^{(3)})=a^{(3)}*(1-a^{(3)}) \\
\delta^{(2)}=(\Theta^{(2)})^T\delta^{(3)}.*g’(z^{(2)}) \quad g’(z^{(2)})=a^{(2)}*(1-a^{(2)}) $$
其中函数$g$为sigmoid函数。
梯度下降(Gradient descent)
有了上面的误差逆向传播过程,现在隐藏层所有神经元处的输出结果的误差都已经得到,接下来对代价函数求偏导得到(求偏导的过程十分复杂,但可以证明其正确性):
$$\frac{\partial J(\Theta)}{\partial \Theta_{ij}^{l}}=a_j^{(l)}\delta_i^{(l+1)}$$
有了偏导数,我们就可以使用梯度下降算法优化参数$\Theta$了。
算法过程
BP算法过程如下:
给定训练集$\{(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),\cdots,(x^{(m)},y^{(m)})\}$
设置$\displaystyle\vartriangle ^{(l)}_{ij}=0($for all $l,i,j)$
for i = 1 to m
$\quad$设置$\displaystyle a^{(1)}=x^{(i)}$
$\quad$进行前向传播计算$\displaystyle a^{(l)}\quad for\quad l=2,3,\cdots,L$
$\quad$使用$y^{(i)}$,计算$\displaystyle \delta^{(L)}=a^{(L)}-y^{(i)}$
$\quad$进行误差逆向传播计算$\displaystyle\delta^{(L-1)},\delta^{(L-2)},\cdots,\delta^{(2)}$
$\displaystyle\quad \vartriangle^{(l)}_{ij}:=\vartriangle^{(l)}_{ij}+a^{(l)}_j\delta_i^{(l+1)}$
$\displaystyle D^{(l)}_{ij}:=\frac{1}{m}\vartriangle^{(l)}_{ij}+\lambda\Theta^{(l)}_{ij} \quad $if$\quad j\neq 0$
$\displaystyle D^{(l)}_{ij}:=\frac{1}{m}\vartriangle^{(l)}_{ij}\quad $if$\quad j= 0$
$\displaystyle\frac{\partial J(\Theta)}{\partial \Theta_{ij}^{l}}=D^{(l)}_{ij}$,再进行梯度下降。
算法须知
梯度检测
对于一个函数来说,通常有两种计算梯度的方式:数值梯度(numerical gradient)和解析梯度(analytic gradient)。数值梯度的优点是容易编程实现,不要求函数可微,然而,数值梯度缺点很明显,通常是近似解,同时求解速度很慢,因此在设计机器学习目标函数时,通常设计成可微的函数,可以快速地求解其解析梯度,同时这个梯度是确切解。
神经网络算法使用反向传播计算目标函数关于每个参数的梯度,可以看做解析梯度。由于计算过程中涉及到的参数很多,反向传播计算的梯度很容易出现误差,导致最后迭代得到效果很差的参数值。
为了确认代码中反向传播计算的梯度是否正确,可以采用梯度检验(gradient check)的方法。通过计算数值梯度,得到梯度的近似值(数值梯度),然后和反向传播得到的梯度(解析梯度)进行比较,若两者相差很小的话则证明反向传播的代码是正确无误的。
函数$J(\theta)$在$\theta$处的梯度值数学定义为:
$$\frac{\mathrm{d}J(\theta)}{\mathrm{d}\theta}=\lim_{\epsilon\rightarrow 0}\frac{J(\theta+\epsilon)-j(\theta-\epsilon)}{2\epsilon}$$
其近似梯度值(数值梯度)为:
$$\frac{\mathrm{d}J(\theta)}{\mathrm{d}\theta}=\frac{J(\theta+\epsilon)-j(\theta-\epsilon)}{2\epsilon}$$
其中$\epsilon$通常被设置为很小的值,一般为$10^{-4}$。
初始化$\Theta$
初始化网络中的权值参数$\Theta$时,不可将其设为相同的值,否则前向传播会得到相等的输出。一般初始化$\Theta$满足$\Theta^{(l)}_{ij}\in [-\epsilon,\epsilon]$,比如:
$\Theta^{1}=$ rand(10,11)*(2*INIT_EPSILON)-INIT_EPSILON;
训练过程
将上面介绍的过程和注意点总结起来,首先需要设计合理神经网络结构,默认1层隐藏层,每个隐藏层神经元的数量通常越多越好。神经网络训练过程如下:
1.随机初始化权值
2.进行前向算法计算所有$\displaystyle x^{(i)}$的$\displaystyle h_{\Theta}(x^{(i)})$。
3.编写代码计算代价函数$\displaystyle J(\Theta)$
4.进行逆向传播计算偏导数$\displaystyle\frac{\partial J(\Theta)}{\partial \Theta_{ij}^{l}}$
5.使用梯度检验来比较使用逆向传播的梯度$\displaystyle\frac{\partial J(\Theta)}{\partial \Theta_{ij}^{l}}$和$\displaystyle J(\Theta)$数值估计的梯度,然后禁用梯度检验代码(否则会严重降低运行速度)
6.使用梯度下降或者其它的高级优化方法,最小化函数$\displaystyle J(\Theta)$,求得最优的权值$\Theta$。